﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;
using Xenta.Utils;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the invoice entity.
    /// </summary>
    /// <remarks><pre>
    /// The entity regarding the disclosure level.
    /// 
    /// + Entire
    ///  | - Payments(of the Extended level)
    ///  + Extended
    ///   + Base
    ///    | - Order(of the Keys level)
    ///    | - Total
    ///    | - PaidAmount
    ///    | - RefundAmount
    ///    | - Flags
    ///    | - UpdatedOn
    ///    | - CreatedOn
    ///    | - IssuedOn
    ///    + Keys
    ///     | - Guid
    ///     + Primary
    ///      | - EntityID
    /// 
    /// Note: upper level includes lower level.
    /// </pre></remarks>
    public class InvoiceEntity : AuditableEntity
    {
        #region Fields

        private DateTime _issuedOn;
        private ICollection<PaymentEntity> _payments;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public InvoiceEntity()
        {
            _issuedOn = DateTime.UtcNow;
            _payments = new List<PaymentEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or set the order.
        /// </summary>
        public virtual OrderEntity Order
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the invoice global unique identifier.
        /// </summary>
        public virtual Guid Guid
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the total.
        /// </summary>
        public virtual decimal Total
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the paid amount.
        /// </summary>
        public virtual decimal PaidAmount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the refund amount.
        /// </summary>
        public virtual decimal RefundAmount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public virtual InvoiceFlags Flags
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the issue date.
        /// </summary>
        public virtual DateTime IssuedOn
        {
            get
            {
                return _issuedOn;
            }
            set
            {
                _issuedOn = value;
            }
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets or sets the payment collection.
        /// </summary>
        public virtual ICollection<PaymentEntity> Payments
        {
            get
            {
                return _payments;
            }
            set
            {
                _payments = value;
            }
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Keys)
                obj["Guid"] = Guid;
            if(level >= DisclosureLevel.Base)
            {
                obj["Order"] = Order.Disclose(DisclosureLevel.Keys, options);
                obj["Total"] = Total;
                obj["PaidAmount"] = PaidAmount;
                obj["RefundAmount"] = RefundAmount;
                obj["Flags"] = Flags.ToString();
                obj["IssuedOn"] = IssuedOn;
            }
            if(level >= DisclosureLevel.Entire)
                obj["Payments"] = Payments.Map(x => x.Disclose(DisclosureLevel.Extended, options));
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapping.
    /// </summary>
    public class InvoiceMapping : EntityMapping<InvoiceEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public InvoiceMapping()
        {
            Table("fwk_Invoices");
            Id(x => x.EntityID, m =>
            {
                m.Column("InvoiceID");
                m.Generator(Generators.Identity);
            });
            ManyToOne(x => x.Order, m =>
            {
                m.Column("OrderID");
                m.ForeignKey("FK_fwk_Invoices_fwk_Orders");
                m.NotNullable(true);
            });
            Property(x => x.Guid, m =>
            {
                m.Unique(true);
                m.Index("IX_fwk_Invoices");
                m.NotNullable(true);
            });
            Property(x => x.Total, m =>
            {
                m.Precision(19);
                m.Scale(4);
                m.NotNullable(true);
            });
            Property(x => x.PaidAmount, m =>
            {
                m.Precision(19);
                m.Scale(4);
                m.NotNullable(true);
            });
            Property(x => x.RefundAmount, m =>
            {
                m.Precision(19);
                m.Scale(4);
                m.NotNullable(true);
            });
            Property(x => x.Flags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.IssuedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.Payments, m =>
            {
                m.Table("fwk_Payments");
                m.Key(k =>
                {
                    k.Column("InvoiceID");
                    k.ForeignKey("FK_fwk_Payments_fwk_Invoices");
                    k.NotNullable(true);
                });
                m.Inverse(true);
                m.BatchSize(10);
            },
            a =>
            {
                a.OneToMany();
            });
        }
    }
}
